﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Text;
using System.Data;

namespace DXL_Library
{
    [Serializable]
    public class DXL_SpreadSheet
    {
        private StringBuilder _logCarga ;

        public bool AplicarFormato(int indiceHC, out string msg)
        {
            return IterarHojaCalculo(this, ACCION.APLICAR_FORMATO, indiceHC, out msg);
        }
        public enum ACCION
        {
            TRAER_DATOS,
            APLICAR_FORMATO,
        }

        public static bool IterarHojaCalculo(DXL_SpreadSheet hc, ACCION accion, int indiceHC, out string msg)
        {
            bool exito;
            int indicePestaña;

            exito = false;

            indicePestaña = 0;

            msg = string.Empty;

            foreach (DXL_Sheet h in hc.Hojas)
            {
                exito = IterarPestaña(h, accion, indicePestaña, indiceHC, out msg);
                if (!exito)
                {
                    break;
                }
                indicePestaña++;
            }

            return exito;
        }
        public static bool IterarPestaña(DXL_Sheet h, ACCION accion, int indicePestaña, int indiceHC, out string msg)
        {
            bool exito;
            int indiceGrilla;

            exito = false;

            indiceGrilla = 0;

            msg = string.Empty;

            if (h.Grillas != null)
            {
                foreach (DXL_Grid g in h.Grillas)
                {
                    exito = IterarGrilla(g, accion, indiceGrilla, indicePestaña, indiceHC, out msg);
                    if (!exito)
                    {
                        break;
                    }
                    indiceGrilla++;
                }
            }

            return exito;
        }




        public static bool IterarGrilla(DXL_Grid g, ACCION accion, int indiceGrilla, int indicePestaña, int indiceHC, out string msg)
        {
            bool exito;


            exito = false;

            if (g == null)
            {
                msg = "La grilla debe ser no nula";
            }
            else
            {
                switch (accion)
                {
                    case ACCION.TRAER_DATOS:
                        exito = TraerDatos(g, indiceGrilla, indicePestaña, indiceHC, out msg);
                        break;

                    case ACCION.APLICAR_FORMATO:
                        exito = DarFormatoDataTable(g.Datos, g.FormatosColumna, out msg);
                        break;
                    default:
                        msg = string.Format("Debe implementar la accion {0}", accion);
                        break;
                }
            }
            return exito;
        }
        public static bool DarFormatoDataTable(DataTable dt, string renglonFormato, out string msg)
        {
            List<string> lstFormatos;

            lstFormatos = Util.RenglonEnListaStrings(renglonFormato);

            return DarFormatoDataTable(dt, lstFormatos, out msg);
        }

        public static bool DarFormatoDataTable(DataTable dt, List<string> lstFormatos, out string msg)
        {
            object obj;
            bool exito;

            exito = false;
            msg = string.Empty;

            if (dt == null)
            {
                throw new ArgumentException("El datatable al que se le dara formato no puede ser null");
            }

            if (dt.Rows != null)
            {

                int numFil;
                int numCol;
                int numFormatos;

                numFil = dt.Rows.Count;
                numCol = dt.Columns.Count;
                numFormatos = lstFormatos.Count;

                if (numCol != numFormatos)
                {
                    msg = string.Format("numColumnas = {0} pero numero de formatos especificados es {1}", numCol, numFormatos);
                }

                if ((numFil > 0) && (numCol > 0))
                {
                    for (int j = 0; j < numFil; j++)
                    {
                        for (int i = 0; i < numCol; i++)
                        {
                            try
                            {
                                obj = dt.Rows[j][i];

                                dt.Rows[j][i] = ValorConFormato(obj, lstFormatos[i]);

                                exito = true;
                            }
                            catch (Exception ex)
                            {
                                exito = false;
                                msg = ex.Message;
                            }

                            if (!exito)
                            {
                                break;
                            }

                        }
                        if (!exito)
                        {
                            break;
                        }
                    }
                    exito = true;
                }
            }

            return exito;
        }
        /*
Formato de cada columna se compone de 
MAXIMO_ANCHO = numero de hasta 3 digitos en caracteres para poder alinear el texto ("023 para 23 caracters de ancho")
PREFIJO = [un caracter de prefijo por ejemplo $] = si no requiere prefijo use "_"
ALINEACON = [Izquierda|Derecha|Centrado] = I|D|C
PRECISION = Solo aplica para decimales = N de 0 a 9 (Decimales de 0 precison es un ENTERO)
POSTFIJO = [el resto de la cadena o un caracter de prefijo por ejemplo "%" o "kWh"]

FORMATO = MAXIMO_ANCHO + PREFIJO + ALINEACON +  PRECISION + POSTFIJO
            
* */
        public static string ValorConFormato(object val, string formato)
        {
            string resp;
            char caracter;
            int ancho;
            string alineacionAncho;
            bool exito;

            resp = string.Empty;

            exito = false;

            if (formato.Length == 8)
            {
                try
                {
                    //AsignarCultura(true);

                    /*ejemplo de formato 
                           "030_T___" = maximo 30 caracteres, sin prefijo, texto (alineado a la izquierda), sin precision y sin postfijo (sin agregarle algo)
                           "010_D04%" = maximo 10 caracteres, sin prefijo, decimales (alineado a la Derecha), 04 decimales y agregarle % 
                           "020$M02_" = maximo 20 caracteres, con prefijo $, Moneda (alineado a la derecho y separado de miles) a la Derecha, 02 decimales y sin posffijo (sin agregarle algo)
                     * */

                    ancho = Int16.Parse(formato.Substring(0, 3));

                    caracter = formato[3];
                    //colocarle prefijo si fue especificado

                    if (caracter != '_')
                    {
                        resp = resp + caracter;
                    }

                    //la alineacion
                    caracter = formato[4];

                    // The constant formatting string.
                    // ... It specifies the padding.
                    // ... A negative number means to left-align.
                    // ... A positive number means to right-align.
                    //
                    //const string format = "{0,-10} {1,10}";

                    if (caracter.ToString().ToUpper() == "I")
                    {
                        alineacionAncho = "{0,-" + ancho + "}";
                    }
                    else if (caracter.ToString().ToUpper() == "D")
                    {
                        alineacionAncho = "{0," + ancho + "}";
                    }
                    else if (caracter.ToString().ToUpper() == "M")
                    {
                        alineacionAncho = "{0," + ancho + ":C}";
                    }
                    else
                    {
                        alineacionAncho = "{0}";
                    }

                    resp = resp + string.Format(alineacionAncho, val);


                    int pos;
                    int numDec;

                    Double nada;

                    if (Double.TryParse(resp, out nada))
                    {
                        //aunque se asigno cultura...
                        pos = resp.IndexOf('.');

                        //..ir a la fija
                        if (pos < 0)
                        {
                            pos = resp.IndexOf(',');
                        }

                        if (pos >= 0)
                        {
                            //limitar el numero de decimales de precision (truncando..no redondeando)
                            numDec = Int16.Parse(formato.Substring(5, 2));
                            resp = resp.Substring(0, pos + numDec + 1);
                        }
                    }

                    caracter = formato[7];
                    //colocarle postfijo si fue especificado
                    if (caracter != '_')
                    {
                        resp = resp + caracter;
                    }


                    exito = true;
                }
                catch
                {
                }

            }
            if (!exito)
            {
                //resp = string.Format("fORMATO INVALIDO especificado {0}", val);
                resp = val.ToString();
            }

            return resp;
        }
        /// <summary>
        /// 
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="listDatos"></param>
        /// <param name="dt"></param>
        /// <param name="renglonFormato">si no quiere especificar formato dejelo en NULL o strin.empty </param>
        /// <param name="msg"></param>
        /// <returns></returns>
        public static bool LlenarDataTableConList<T>(List<T> listDatos, DataTable dt, string renglonFormato, out string msg)
        {
            bool exito;
            int numCol;
            DataRow dr;
            int i;
            bool sinFormato;
            object obj;
            List<string> lstFormatos;
            string formatoCol;
            int numFormatos;
            bool error;

            exito = false;
            sinFormato = Util.EsCadenaVacia(renglonFormato);
            msg = string.Empty;

            if (dt == null)
            {
                throw new ArgumentException("El datatable al que se le dara formato no puede ser null");
            }



            numCol = dt.Columns.Count;
            lstFormatos = null;

            //si TIENE FORMATO
            if (!sinFormato)
            {
                lstFormatos = Util.RenglonEnListaStrings(renglonFormato);

                if (lstFormatos != null)
                {
                    numFormatos = lstFormatos.Count;

                    if (numCol != numFormatos)
                    {
                        msg = string.Format("El numero de columnas es {0} pero el numero de formatos especificados es {1}\n{2}", numCol, numFormatos, renglonFormato);
                    }
                    else
                    {
                        exito = true;
                    }
                }
                else
                {
                    sinFormato = true;
                }
            }
            else
            {
                exito = true;
            }

            if (exito && (listDatos != null))
            {
                IRowRender aux;
                error = true;

                try
                {
                    aux = listDatos[0] as IRowRender;
                    if (aux != null)
                    {
                        error = false;
                    }
                }
                catch
                {

                }

                if (error)
                {
                    throw new ArgumentException("El tipo {0} debe implementar IRepresentableEnFila");
                }
                foreach (IRowRender an in listDatos)
                {
                    dr = dt.NewRow();

                    for (i = 0; i < numCol; i++)
                    {
                        obj = an.ValueForColumn(i);

                        //si TIENE FORMATO
                        if (!sinFormato)
                        {
                            formatoCol = lstFormatos[i];
                            dr[i] = ValorConFormato(obj, formatoCol);

                        }
                        else
                        {
                            dr[i] = obj;
                        }
                    }


                    dt.Rows.Add(dr);
                }
                exito = true;
            }


            return exito;
        }

        private static bool TraerDatos(DXL_Grid g, int indiceGrilla, int indicePestaña, int indiceHC, out string msg)
        {
            msg = string.Empty;

            //Aca se puede implementar diferentes formas de llenar las grillas de cada pestaña
            return false;
        }
        public string ObtenerLogCarga()
        {
            return _logCarga.ToString(); 
        }
        public DXL_LibraryParameters parametros;

        public void AgregarLogCarga(string msg)
        {
            if (parametros.DEBUG)
            {
                _logCarga.AppendLine(msg);
            }
        }

        private StringBuilder _logErrores;

        public string ObtenerLogErrores()
        {
            return _logErrores.ToString();
        }

        public void AgregarLogErrores(string msg)
        {
            _logErrores.AppendLine(msg);
        }

        private string _nombre;

        public string Nombre
        {
            get { return _nombre; }
            set { _nombre = value; }
        }


        public DXL_SpreadSheet()
        {
            _logCarga = new StringBuilder();
            _logErrores = new StringBuilder();
        }

        public bool sinErrores
        {
            get
            {
                bool resp;

                resp = (_logErrores.Length == 0);
                return resp;
            }

        }
        public bool conErrores
        {
            get
            {
                return !sinErrores;
            }

        }
        private string _rutaArch;

        public string RutaArch
        {
            get { return _rutaArch; }
            set { _rutaArch = value; }
        }

        public List<DXL_Sheet> Hojas;


        public int NumHojasRequeridas()
        {
            int resp;

            resp = 0;

            if (this.Hojas != null)
            {
                foreach (DXL_Sheet h in this.Hojas)
                {
                    if (h.EsRequerida)
                    {
                        resp++;
                    }
                }
            }
            return resp;
        }
        public override string ToString()
        {
            string resp;

            resp = this.RutaArch + "\n";

            if (Hojas != null)
            {
                foreach (DXL_Sheet h in Hojas)
                {
                    resp += h.ToString();
                }
            }

            return resp;
        }

    }
}